﻿#include "AudioPlayer.h"

#include "Audio/Audio.h"
#include "Math/Math.h"

TSharedObjectPtr<RAudio> RAudioPlayer::GetAudio() const
{
    return Audio;
}

void RAudioPlayer::SetAudio(TSharedObjectPtr<RAudio> InAudio)
{
    if(IsOpen())
    {
        Close();
    }

    if(IsPlaying())
    {
        Abort();
    }

    Audio=InAudio;

    FrameCount=Audio->GetPCMData().Num()/GetFrameDataSize();
}

int64_t RAudioPlayer::GetFrameDataSize()
{
    return Audio->GetNumChannels() * Audio->GetBitsPerSample() / 8;
}

void RAudioPlayer::Open()
{
    Player.DataGetter.Bind(this, &RAudioPlayer::CopyData);


    //PlayedFrameNum=0;

    Player.OpenStream(
        Audio->GetSampleRate(),
        Audio->GetNumChannels(),
        Audio->GetBitsPerSample()
    );
}

void RAudioPlayer::Close()
{
    Player.CloseStream();
}

bool RAudioPlayer::IsOpen()
{
    return Player.IsStreamOpened();
}

void RAudioPlayer::Play()
{
    Player.StartStream();
}

void RAudioPlayer::Pause()
{
    Player.StopStream();
}

void RAudioPlayer::Abort()
{
    PlayedFrameNum=0;
    Player.StopStream();
}

bool RAudioPlayer::IsPlaying()
{
    return Player.IsStreamRunning();
}

void RAudioPlayer::SetCurrentTime(float InTime)
{
    PlayedFrameNum=CMath::Clamp(InTime*Audio->GetSampleRate(), 0, FrameCount);
}

float RAudioPlayer::GetCurrentTime()
{
    return PlayedFrameNum/(double)Audio->GetSampleRate();
}

float RAudioPlayer::GetCurrentTimePercent()
{
    return PlayedFrameNum/(double)FrameCount;
}

void RAudioPlayer::SetCurrentTimePercent(float InPercent)
{
    PlayedFrameNum=CMath::Clamp(InPercent*FrameCount, 0, FrameCount);
}

uint64_t RAudioPlayer::CopyData(void *outputBuffer, uint64_t nBufferFrames)
{
    uint64_t CopyFrameNum= CMath::Min(
        nBufferFrames
        ,FrameCount-PlayedFrameNum);

    switch(Audio->GetBitsPerSample())
    {
    case 8:
    {
        int8_t *Buffer = (int8_t*)outputBuffer;
        uint64_t DataNum=CopyFrameNum * Audio->GetNumChannels();

        uint8_t* DataStart = Audio->GetPCMData().Data()+ PlayedFrameNum*GetFrameDataSize();

        for (int i = 0; i < DataNum; i++)
        {
            int8_t Data= *((int8_t*)DataStart +i);
            Buffer[i] = Data*Volume;
        }
    }
    break;

    case 16:
    {
        int16_t *Buffer = (int16_t*)outputBuffer;
        uint64_t DataNum= CopyFrameNum*Audio->GetNumChannels();
        
        uint8_t* DataStart = Audio->GetPCMData().Data()+ PlayedFrameNum*GetFrameDataSize();

        for (int i = 0; i < DataNum; i++)
        {
            int16_t Data= *((int16_t*)DataStart+i);
            Buffer[i] = Data*Volume;
        }

    }
    break;
    case 24:
    {
        int8_t *Buffer = (int8_t*)outputBuffer;
        uint64_t DataNum= CopyFrameNum*Audio->GetNumChannels();
        
        uint8_t* DataStart = Audio->GetPCMData().Data()+ PlayedFrameNum*GetFrameDataSize();

        for (int i = 0; i < DataNum; i++)
        {
            int32_t Data = 0;
            Data |= DataStart[i*3+2] << 16;
            Data |= DataStart[i*3+1] << 8;
            Data |= DataStart[i*3];

            Data*=Volume;

            Buffer[i*3] = Data & 0xFF;
            Buffer[i*3+1] = (Data >> 8) & 0xFF;
            Buffer[i*3+2] = (Data >> 16) & 0xFF;
        }
    }

    break;

    case 32:
    {
        int32_t *Buffer = (int32_t*)outputBuffer;
        uint64_t DataNum= CopyFrameNum*Audio->GetNumChannels();
        
        uint8_t* DataStart = Audio->GetPCMData().Data()+ PlayedFrameNum*GetFrameDataSize();

        for (int i = 0; i < DataNum; i++)
        {
            int32_t Data= *((int32_t*)DataStart+i);
            Buffer[i] = Data*Volume;
        }
    }
    break;

    }


    PlayedFrameNum+=CopyFrameNum;

    //通知播放结束
    //事实上并没有完全播放结束，最后这几帧还没有播放
    if(PlayedFrameNum==FrameCount)
    {
        PlayedFrameNum=0;
        OnPlayFinished.Broadcast();
    }

    return CopyFrameNum;
}
